#include "spipe.h"

SPipe::SPipe()
{
    p_mx_quee = PTHREAD_MUTEX_INITIALIZER;
    p_exit_flag = 0;



}

SPipe::~SPipe()
{
    //dtor
}

int SPipe::PortOpen( u16 port )
{
    LOGP2("Opening port [%d]...",port);
    p_port = port;
    pthread_create(&p_thr_accept,0,&SPipe::th_accept,(void*)this);
    return 0;

}

void *SPipe::th_accept( void * param)
{
    SPipe *pipe = (SPipe*)param;

    memset(&pipe->p_hints, 0, sizeof pipe->p_hints);
    pipe->p_hints.ai_family = AF_UNSPEC;  // use IPv4 or IPv6, whichever
    pipe->p_hints.ai_socktype = SOCK_STREAM;
    pipe->p_hints.ai_flags = AI_PASSIVE;     // fill in my IP for me

    char buff[32];
    sprintf(buff,"%d",pipe->p_port);

    getaddrinfo("127.0.0.1", buff, &pipe->p_hints, &pipe->p_res);

// make a socket:

    pipe->p_socket = socket(pipe->p_res->ai_family, pipe->p_res->ai_socktype, pipe->p_res->ai_protocol);

// bind it to the port we passed in to getaddrinfo():

    int res = bind(pipe->p_socket, pipe->p_res->ai_addr, pipe->p_res->ai_addrlen);

    if (res == -1)
    {
        LOGP1("BIND Error.");
        pipe->p_error(ER_BIND);
        return 0;
    }

    res = listen(pipe->p_socket,15);

    if (res == -1)
    {
        LOGP1("Listen Error.");
        pipe->p_error(ER_LISTEN);
    }
    LOGP1("Port opened.");

    socklen_t addr_size = sizeof (pipe->p_remoteaddr);

    while (!pipe->p_exit_flag)
    {
        int res = accept(pipe->p_socket,(struct sockaddr *)&pipe->p_remoteaddr,&addr_size);
        if (res == -1)
        {
            if (pipe->p_exit_flag)       // clean exit.
            {
                LOGP1("Accepting socket closed.");
                return 0;
            }
            // TODO Stop accepting
            pipe->p_error(ER_ACCEPT);
            return (void*)0;
        }

        sockaddr_in addr;
        int addrlen = sizeof(addr);
        int res2 = getpeername(res,(sockaddr*)&addr,&addrlen);
        if (res2 == -1)
        {
            LOGP1("WARNING Getpeername failed");
            LOGP1("New connection accepted.");
        }
        else
        {
//            inet_ntop(addr);
            LOGP2("Connection arrived from [%s]...",inet_ntoa(addr.sin_addr));

        }

        ENTER_CS (pipe->p_mx_quee);
        pipe->p_quee.push_back(res);
        LEAVE_CS (pipe->p_mx_quee);

        if (!pipe->onAccept.empty())
        {
            pipe->onAccept(pipe,0xFF);    // new connection arrived
        }


    }

    return 0;

}

void SPipe::p_error(int err_code, string err)
{
    if (!onError.empty())
    {
        onError(this,err_code);
        return;
    }
    LOGP1("[FATAL] Unhandled error in spipe");
    EXCEX(err_code, err);
}

int SPipe::IsReady()
{
    ENTER_CS (p_mx_quee );
    if (p_quee.size())
    {
        LEAVE_CS(p_mx_quee);
        return 1;
    }
    LEAVE_CS(p_mx_quee);
    return 0;
}

int SPipe::Accept(Pipe &pipe)
{
    ENTER_CS (p_mx_quee );
    if (!p_quee.size())
    {
        LEAVE_CS (p_mx_quee);
        p_error(ER_EMPTY_QUEE);
        pipe.setSocket(0);
        return -1;
    }
    int sock = *(p_quee.begin());
    p_quee.erase(p_quee.begin());
    LEAVE_CS(p_mx_quee);
    pipe.setSocket(sock);
    pipe._only_read = 1;
    pipe.startReading();
    Sleep(1);
    return 0;
}
